package id;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECCurve.Fp;
import org.bouncycastle.math.ec.ECPoint;

public class Hash {

    private static final double delta = 100000;

    private static BigInteger fx(BigInteger x, BigInteger a, BigInteger b) {
        return x.pow(3).add(a.multiply(x)).add(b);
    }

    private static int fixBound() throws NoSuchAlgorithmException {
        double log = Math.log10(delta) / Math.log10(2);
        int I = (int) Math.ceil(Math.log10(log) / Math.log10(2));
        return (int) Math.pow(2, I);
    }

    public static ECPoint hash(String message, ECParameterSpec curve) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            ECCurve.Fp fpCurve = (Fp) curve.getCurve();
            BigInteger p = fpCurve.getQ();
            BigInteger h = curve.getH();
            int bound = fixBound();
            for (int i = 0; i < bound; i++) {
                String m = String.valueOf(i).concat(message);
                byte[] hashedMessage = md.digest(m.getBytes());
                BigInteger x = new BigInteger(hashedMessage).mod(p);
                BigInteger y = fx(x, curve.getCurve().getA().toBigInteger(), curve.getCurve().getB().toBigInteger()).mod(p);
                BigInteger sqRoot = y.modPow((p.add(BigInteger.ONE).divide(BigInteger.valueOf(4))), p);
                if (sqRoot.modPow(BigInteger.valueOf(2), p).equals(y)) {
                    return fpCurve.createPoint(x, sqRoot, false).multiply(h);
                }
            }
        } catch (NoSuchAlgorithmException e) {
            System.exit(0);
        }
        return null;
    }
}